﻿' Copyright 2008 Chris Varley (http://www.contractdriven.net/)
'
' Licensed under the Apache License, Version 2.0 (the "License");
' you may not use this file except in compliance with the License.
' You may obtain a copy of the License at
'
'    http://www.apache.org/licenses/LICENSE-2.0
'
' Unless required by applicable law or agreed to in writing, software
' distributed under the License is distributed on an "AS IS" BASIS,
' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
' See the License for the specific language governing permissions and
' limitations under the License.

'Import the ContractDriven Namespace
Imports ContractDriven

Namespace ContractExample

    Class ExampleClass
        Inherits ContractBoundObject

        'some private variables 
        Private _myInt As Integer
        Private _myString As String = String.Empty

        Public Sub New()
            'You can either explicity define logic for an Invariant Check 
            Contract.Invariant(Me, Function() _myInt > -1 AndAlso _myInt < 101, "_myInt should be between 0 and 100")

            'or use one of the built in checks 
            '(these checks can be used by any contract type, "Require", "Ensure", "Invariant") 
            Contract.Invariant(Me, Function() Assert.IsInRange(_myInt, 0, 100))

            'An invariant follows the same pattern as other contracts, but uses a delegate 
            'rather than inline execution (as it can be evaluated at any point.) 
            Contract.Invariant(Me, Function() _myInt <> 42, "_myInt must not equal 42")
            Contract.Invariant(Me, Function() Assert.IsLengthInRange(_myString, 0, 20))
        End Sub

        Public Property MyInt() As Integer
            Get
                Return _myInt
            End Get
            Set(ByVal value As Integer)
                'you can assign values as normal... 
                _myInt = value
                '...in this case invariants will be evaluated after the method has returned. 
                'Or, you can assign the value to the property field using the contract. 
                'This checks invariants immediatly and is useful in fast fail situations. 
                Contract.Assign(Me, _myInt, value)
            End Set
        End Property

        Public Sub SetMyIntAndMyString(ByVal newInt As Integer, ByVal newString As String)
            Contract.Require(Assert.IsInRange(newInt, 0, 100))
            Contract.Require(Assert.IsNotNullOrEmpty(newString))

            _myInt = newInt
            _myString = newString

            Contract.Ensure(_myInt = newInt)
            Contract.Ensure(_myString = newString)
        End Sub

        Public Sub IncrementMyInt()
            'track the object 
            Dim key As Guid = Contract.Track(_myInt)

            _myInt += 1

            'ensure that the logic performed correctly 
            Contract.Ensure(_myInt = CInt(Contract.Before(key)) + 1, "_myInt should equal 1 more than original value")
        End Sub

    End Class
End Namespace